package sfsu.memopad;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import sfsu.memopad.AddGroupMembers.NetworkCall;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;
import android.os.Process;

/*
 * Performs a continuous check of task locations versus current location.
 * Upon reaching 500 meters of a task locations, a notification to the user
 * is sent. 
 */
public class GpsService extends Service {
	LocationManager locationManager;
	Geocoder coder;

	private ArrayList<Locator> proximityLocations = new ArrayList<Locator>();
	private ArrayList<TaskData> taskListData = new ArrayList<TaskData>();
	private String newData = "None";
	
	private static int Notification_ID = 0;
	public static int notify = 14;

	private CountDownTimer timer;
	
	private String server = "http://10.0.2.2:9226/";

	@Override
	public void onCreate() {
		Log.d("GpsService", "Service Starting.");
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		newData = intent.getAction();
		getTasksEvery5Minutes();
		Log.d("GpsService", "onStartCommand done.");
		return START_NOT_STICKY;
	}

	@Override
	public void onDestroy() {
		Log.d("GpsService", "Destroyed.");
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	// Refresh task list.
	//private ArrayList<TaskData> refreshTaskList() {
	private void refreshTaskList() {
		//ArrayList<TaskData> taskListData = new ArrayList<TaskData>();
		taskListData.clear();
		if (!newData.contentEquals("")) {
			String parts[] = newData.split("<taskbreak>");
			for (int x = 0; x < parts.length; x++) {
				taskListData.add(new TaskData(parts[x]));
			}
		}
		//return taskListData;
	}
	
	// Refresh proximity location list.
	private void updateProximityLocations () {
		Log.d("GpsService", "Proximity locations updating.");
		proximityLocations.clear();
		//ArrayList<TaskData> taskListData = refreshTaskList();
		refreshTaskList();
		for (int x = 0; x < taskListData.size(); x++) {
			Locator checkPoint = new Locator(taskListData.get(x).getTaskId(), taskListData.get(x).getTitle(), taskListData.get(x).getLatitude(), taskListData.get(x).getLongitude());
			proximityLocations.add(checkPoint);
		}
	}

	private LocationListener locationListener = new LocationListener() {
		public void onLocationChanged(Location location) {
			Log.d("Listener", "onLocationChanged: Location changed to: " + location.getLongitude() + ", " + location.getLatitude());
			proximityCheck(location);
		}

		public void onProviderDisabled(String provider) {}
		public void onProviderEnabled(String provider) {}
		public void onStatusChanged(String provider, int status, Bundle extras) {}
	};

	public void doOnLocationChange() {
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		coder = new Geocoder(getApplicationContext());
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
	}

	private void sendNotification(int position, String title) {
		// Get a reference to the NotificationManager
		Log.d("Notification", "sendNotification called.");
		String ns = Context.NOTIFICATION_SERVICE;
		NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
		
		int icon = R.drawable.notes_add;// change that
		CharSequence tickerText = "Task update";
		
		long when = System.currentTimeMillis();
		Notification notification = new Notification(icon, tickerText, when);

		// Define the notification's message and PendingIntent
		Context context = getApplicationContext();
		CharSequence contentTitle = title;
		CharSequence contentText = "Task update!";
		Intent notificationIntent = new Intent(GpsService.this, MemoPadActivity.class);
		notify = 5;
		PendingIntent contentIntent = PendingIntent.getActivity(GpsService.this, 0, notificationIntent, 0);
		notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
		Notification_ID += 1;
		notification.flags |= Notification.FLAG_AUTO_CANCEL;
		mNotificationManager.notify(Notification_ID, notification);
		
		Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		vib.vibrate(3000);
		
		Log.d("Notification", "sendNotification done.");
	}

	public void proximityCheck(Location location) {
		updateProximityLocations();
		Log.d("Proximity", "proximityLocation size: " + proximityLocations.size());
		
		for (int x = 0; x < proximityLocations.size(); x++) {
			Location goalLocation = proximityLocations.get(x).getLocation();
			float distanceBetweenLocations = location.distanceTo(goalLocation);

			String showText = "Goal Location: " + goalLocation.getLongitude() + ", " + goalLocation.getLatitude() + " -> Distance: " + distanceBetweenLocations;
			Log.d("Proximity", showText);

			if (distanceBetweenLocations <= 500) {
				Log.d("GpsService", "Requesting notification for " + proximityLocations.get(x).getTitle());
				taskListData.get(x).setIsNotificationOn(false);
				new NetworkCall().execute(server + "EDIT<CMD>" + taskListData.get(x).getOwner() + "<CMD>" + convertStringForNetworkSend(taskListData.get(x).toString()));
				sendNotification(x, proximityLocations.get(x).getTitle());
				proximityLocations.remove(x);
				taskListData.remove(x);
				x--;
			}
		}
		
		Log.d("Proximity", "Proximity check, leaving.");
	}

	public void getTasksEvery5Minutes() {
		timer = new CountDownTimer(1000 * 60 * 5, 1000 * 60) {
			public void onTick(long millisUntilFinished) {
				synchronized (this) {
					try {
						doOnLocationChange();
					} catch (Exception e) {
					}
				}
			}

			public void onFinish() {
				timer.start();
			}
		}.start();
	}
	
	private String convertStringForNetworkSend(String input) {
		return input.replace("\n", "<CR>");
	}
	
	/*
	 * Networking: set up connection to server;
	 */
	public class NetworkCall extends AsyncTask<String, Void, String> {
		@Override
		protected void onPreExecute() {
			Log.i("GpsService", "NetworkCall.onPreExecute");
		}

		/*
		 * Opens a Http connection to a server.
		 */
		private InputStream OpenHttpConnection(String urlString) throws IOException {
			InputStream in = null;
			int response = -1;

			try {
				URL url = new URL(urlString);
				URLConnection conn = url.openConnection();

				if (!(conn instanceof HttpURLConnection))
					throw new IOException("Not an HTTP connection");
				try {
					HttpURLConnection httpConn = (HttpURLConnection) conn;
					httpConn.setAllowUserInteraction(false);
					httpConn.setInstanceFollowRedirects(true);
					httpConn.setRequestMethod("GET");
					httpConn.connect();
					response = httpConn.getResponseCode();
					if (response == HttpURLConnection.HTTP_OK) {
						in = httpConn.getInputStream();
					}
				} catch (Exception ex) {
					Log.d("GpsService", "NetworkCall: " + ex.getLocalizedMessage());
					throw new IOException("Error connecting");
				}
			} catch (MalformedURLException e) {
				Log.d("GpsService", "NetworkCall, Error opening URL: " + e);
			}
			return in;
		}

		/*
		 * Pulls string from server.
		 */
		private String DownloadText(String URL) {
			int BUFFER_SIZE = 2000;
			InputStream in = null;
			try {
				in = OpenHttpConnection(URL);
			} catch (IOException e) {
				Log.d("GpsService", "NetworkingActivity: " + e.getLocalizedMessage());
				return "";
			}

			InputStreamReader isr = new InputStreamReader(in);
			int charRead;
			String str = "";
			char[] inputBuffer = new char[BUFFER_SIZE];
			try {
				while ((charRead = isr.read(inputBuffer)) > 0) {
					// ---convert the chars to a String---
					String readString = String
							.copyValueOf(inputBuffer, 0, charRead);
					str += readString;
					inputBuffer = new char[BUFFER_SIZE];
				}
				in.close();
			} catch (IOException e) {
				Log.d("GpsService", "NetworkingActivity: " + e.getLocalizedMessage());
				return "";
			}
			return str;
		}

		// Set up DownloadText as occurs in the background.
		@Override
		protected String doInBackground(String... urls) {
			Log.i("GpsService", "NetworkCall.doInBackgroup: " + urls);
			return DownloadText(urls[0]);
		}

		@Override
		protected void onPostExecute(String result) {}
	}
}
